import type { TaskProps, FlattenedTask, TaskMode } from "../types";
import { clsx, type ClassValue } from "clsx";
import type { Dayjs } from "dayjs";
import { twMerge } from "tailwind-merge";
import { GanttConsts } from "../constants";

/**
 * 将树形任务数据扁平化为一维数组
 * @param tasks 树形任务数据
 * @param expandedTasks 展开的任务ID集合
 * @param level 当前层级
 * @returns 扁平化的任务数组
 */
export function flattenTasks(
  tasks: TaskProps[],
  expandedTasks: Set<string>,
  level: number = 0
): FlattenedTask[] {
  const result: FlattenedTask[] = [];

  for (const task of tasks) {
    const hasChildren = Boolean(task.children && task.children.length > 0);
    const expanded = expandedTasks.has(task.id);

    // 添加当前任务
    result.push({
      ...task,
      level,
      expanded,
      visible: true,
    });

    // 如果有子任务且已展开，递归处理子任务
    if (hasChildren && expanded && task.children) {
      const childTasks = flattenTasks(task.children, expandedTasks, level + 1);
      result.push(...childTasks);
    }
  }

  return result;
}

/**
 * 计算虚拟滚动的可见项目
 * @param items 所有项目
 * @param containerHeight 容器高度
 * @param itemHeight 单个项目高度
 * @param scrollTop 滚动位置
 * @returns 可见项目的索引范围和偏移量
 */
export function calculateVisibleItems(
  items: FlattenedTask[],
  containerHeight: number,
  scrollTop: number
) {
  const startIndex = Math.floor(scrollTop / GanttConsts.ITEM_HEIGHT);
  const endIndex = Math.min(
    startIndex + Math.ceil(containerHeight / GanttConsts.ITEM_HEIGHT) + 1,
    items.length - 1
  );

  // 计算可见区域的偏移量，确保虚拟滚动的正确定位
  const offsetY = startIndex * GanttConsts.ITEM_HEIGHT;
  const totalHeight = items.length * GanttConsts.ITEM_HEIGHT;

  return {
    startIndex: Math.max(0, startIndex),
    endIndex,
    offsetY,
    totalHeight,
    visibleItems: items.slice(Math.max(0, startIndex), endIndex + 1),
  };
}

/**
 * 初始化任务的展开状态
 * @param tasks 任务数组
 * @returns 默认展开的任务ID集合
 */
export function getInitialExpandedTasks(tasks: TaskProps[]): Set<string> {
  const expanded = new Set<string>();

  function traverse(taskList: TaskProps[]) {
    for (const task of taskList) {
      if (task.children && task.children.length > 0) {
        // 默认展开第一层
        if ((task.level ?? 0) === 0) {
          expanded.add(task.id);
        }
        traverse(task.children);
      }
    }
  }

  traverse(tasks);
  return expanded;
}

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

export function getTimeUnitWidth(taskMode: TaskMode): number {
  switch (taskMode) {
    case "Day":
      return 100;
    case "Week":
      return 35;
    case "Month":
      return 10;
    case "Quarter":
      return 5;
    case "Year":
      return 2;
  }
}

export function getTaskBarPosition(taskMode: TaskMode, tasksStart: Dayjs, start: Dayjs, end: Dayjs) {
  let startDate = tasksStart;
  switch (taskMode) {
    case "Week":
      startDate = startDate.startOf('isoWeek');
      break;
    case "Month":
      startDate = startDate.startOf('month');
      break;
    case "Quarter":
      startDate = startDate.startOf('quarter');
      break;
    case "Year":
      startDate = startDate.startOf('year');
      break;
    default:
      startDate = startDate.startOf("day");
      break;
  }
  const timeUnitWidth = getTimeUnitWidth(taskMode);
  const taskBarWidth = (end.diff(start, "day") + 1) * timeUnitWidth;
  const taskBarLeft = start.diff(startDate, "day") * timeUnitWidth;
  return [taskBarWidth, taskBarLeft];
}